package com.interceptor;

import java.io.PrintWriter;

import com.alibaba.fastjson.JSONObject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.http.HttpStatus;

import com.annotation.IgnoreAuth;
import com.entity.TokenEntity;
import com.service.TokenService;

/**
 * 权限(Token)验证拦截器
 * 该拦截器主要用于检查请求中的Token是否合法，判断是否有权限访问接口
 * 如果没有Token或Token无效，则返回401错误，提示用户需要登录
 * 如果Token有效，放行请求并将用户信息存入Session
 *
 * @author team10
 */
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {

    // 定义Token在Header中的key
    public static final String LOGIN_TOKEN_KEY = "Token";

    // 注入Token服务，用于验证Token是否合法
    @Autowired
    private TokenService tokenService;

    /**
     * 请求前的处理方法
     * 主要用于检查请求中的Token是否合法
     *
     * @param request 请求对象
     * @param response 响应对象
     * @param handler 处理器对象
     * @return 如果请求合法，返回true，表示放行；否则返回false，表示阻止请求
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 设置允许跨域的请求头
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with,request-source,Token, Origin,imgType, Content-Type, cache-control,postman-token,Cookie, Accept,authorization");
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));

        // 跨域时，首先会发送一个OPTIONS请求，这里直接返回正常的状态
        if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
            response.setStatus(HttpStatus.OK.value());
            return false;
        }

        // 获取请求处理方法中的@IgnoreAuth注解
        IgnoreAuth annotation;
        if (handler instanceof HandlerMethod) {
            annotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class);
        } else {
            // 如果不是HandlerMethod类型的请求，直接放行
            return true;
        }

        // 获取请求头中的Token
        String token = request.getHeader(LOGIN_TOKEN_KEY);

        // 如果该接口方法被标注了@IgnoreAuth注解，则直接放行
        if(annotation != null) {
            return true;
        }

        TokenEntity tokenEntity = null;
        if(StringUtils.isNotBlank(token)) {
            // 如果Token存在，从Token服务中获取TokenEntity
            tokenEntity = tokenService.getTokenEntity(token);
        }

        if(tokenEntity != null) {
            // Token有效，用户信息存入Session
            request.getSession().setAttribute("userId", tokenEntity.getUserid());
            request.getSession().setAttribute("role", tokenEntity.getRole());
            request.getSession().setAttribute("tableName", tokenEntity.getTablename());
            request.getSession().setAttribute("username", tokenEntity.getUsername());
            // 允许请求继续
            return true;
        }

        // 如果Token无效，返回401错误，提示用户需要登录
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try {
            writer = response.getWriter();
            writer.print(JSONObject.toJSONString(R.error(401, "请先登录")));
        } finally {
            if(writer != null){
                writer.close();
            }
        }

        // 如果Token无效，则返回false，阻止请求继续
        return false;
    }
}
